!function(window, fn) {
	if ('function' === typeof define && define.amd) {
		define([], function() {
			return fn(window);
		});
	} else {
		window.utils = window._$ = fn(window);
	}
}(window, function(window) {
	if (!String.prototype.contains) {
		String.prototype.contains = function(str) {
			return new RegExp(str).test(this);
		};
	}
	var os = Object.prototype.toString, as = Array.prototype.slice,
	// 工具类
	_$ = utils = {
		isNum: function(num) {
			return os.call(num) === '[object Number]';
		},
		isFunction: function(fn) {
			return os.call(fn) === '[object Function]';
		},
		isArray: function(arr) {
			return os.call(arr) === '[object Array]';
		},
		getRandomString: function() {
			return Math.random().toString(36).substring(2);
		},
		// 对象继承
		extendProto: function(B, A) {
			var F = function() {
			};
			F.prototype = A.prototype;
			var f = new F();
			f.constructor = B;
			// 缓存父级对象原型
			f.__parentProto__ = A.prototype;
			// 执行父级对象原型方法
			f.__super__ = function(name) {
				var p = f.__parentProto__, executed = false, args = as.call(arguments, 1);
				while (p.__parentProto__ || p[name]) {
					if (p[name]) {
						p[name].apply(this, args);
						executed = true;
						break;
					} else {
						p = p.__parentProto__;
					}
				}
				if (!executed) {
					throw new Error('The super function \'' + name + '\' does not exist.');
				}
			};
			B.prototype = f;
		},
		// 对事件函数包装，方便阻止事件冒泡
		_packFunction: function(fn) {
			if (fn.__original__) {
				return fn.__original__;
			}
			var f = function(e) {
				var context = this, args = as.call(arguments, 0);
				if (fn.apply(context, args) === false) {
					e = e || window.event;
					// 阻止事件冒泡
					if (e && e.stopPropagation) {
						e.stopPropagation();
					} else {
						window.event.cancelBubble = true;
					}
					// 阻止默认事件
					if (e && e.preventDefault) {
						e.preventDefault();
					} else {
						window.event.returnValue = false;
					}
				}
			};
			fn.__original__ = f;
			return f;
		},
		// 事件绑定
		on: function(dom, type, fn) {
			if (window.addEventListener) {
				_$.on = function(dom, type, fn) {
					var f = _$._packFunction(fn);
					_$.each(type.split(/\s+/), function(index, t) {
						dom.addEventListener(t.toString(), f, false);
					});
				};
			} else if (window.attachEvent) {
				_$.on = function(dom, type, fn) {
					var f = _$._packFunction(fn);
					_$.each(type.split(/\s+/), function(index, t) {
						dom.attachEvent('on' + t.toString(), f);
					});
				};
			} else {
				_$.on = function(dom, type, fn) {
					var f = _$._packFunction(fn);
					_$.each(type.split(/\s+/), function(index, t) {
						dom['on' + t.toString()] = f;
					});
				};
			}
			_$.on(dom, type, fn);
		},
		// 事件委托
		delegate: function(dom, target, type, fn) {
			var f = _$._packFunction(fn),
			// 委托方法
			_delegate = function(e) {
				e = e || window.event;
				var t = e.target || e.srcElement, parentNode = t;
				while (t !== dom) {
					// id class tag
					if ((/^#/.test(target) && t.id === target.substring(1)) || (/^\./.test(target) && t.className.contains(target.substring(1))) || t.tagName.toLowerCase() === target.toLowerCase()) {
						f.call(t, e);
						break;
					}
					t = t.parentNode;
				}
			};
			_$.on(dom, type, _delegate);
		},
		remove: function(dom, type, fn) {
			if (window.removeEventListener) {
				_$.remove = function(dom, type, fn) {
					var f = fn.__original__ || fn;
					_$.each(type.split(/\s+/), function(index, t) {
						dom.removeEventListener(t.toString(), f, false);
					});
				};
			} else if (window.detachEvent) {
				_$.remove = function(dom, type, fn) {
					var f = fn.__original__ || fn;
					_$.each(type.split(/\s+/), function(index, t) {
						dom.detachEvent('on' + t.toString(), f);
					});
				};
			} else {
				_$.remove = function(dom, type, fn) {
					_$.each(type.split(/\s+/), function(index, t) {
						dom['on' + t.toString()] = null;
					});
				};
			}
			_$.remove(dom, type, fn);
		},
		// 复制/扩展对象
		extend: function() {
			var i = 1, len = arguments.length, target = arguments[0], j, value, valueType;
			// 只有一个参数时，复制对象
			if (i === len) {
				target = {};
				i--;
			}
			for (; i < len; i++) {
				_$.each(arguments[i] || {}, function(key, value) {
					valueType = Object.prototype.toString.call(value);
					if ("[object Array]" === valueType) {
						target[key] = [];
						_$.extend(target[key], value);
					} else if ("[object Object]" === valueType) {
						target[key] = {};
						_$.extend(target[key], value);
					} else {
						target[key] = value;
					}
				});
			}
			return target;
		},
		// 数组、对象迭代器
		each: function(o, fn) {
			var argType = Object.prototype.toString.call(o);
			if (argType === '[object Object]' || argType === '[object Array]') {
				for (var key in o) {
					if (fn.call(o[key], key, o[key])) {
						break;
					}
				}
			} else {
				throw new Error("无法遍历的数据类型");
			}
		},
		// 节流器，间隔时间内连续相同的操作仅执行最后一次
		throttle: function() {
			var isClear = arguments[0], fn;
			if (typeof isClear === 'boolean') {
				fn = arguments[1];
				fn.__throttleId && clearTimeout(fn.__throttleId);
			} else {
				fn = isClear;
				var param = arguments[1], p = _$.extend({
					context: null,
					args: [],
					time: 300
				}, param);
				arguments.callee(true, fn);
				fn.__throttleId = setTimeout(function() {
					fn.apply(p.context, p.args);
				}, p.time);
			}
		},
		// 缓行器，连续相同的操作每间隔一段时间执行一次
		amble: function() {
			var fn = arguments[0], param = arguments[1], p = _$.extend({
				context: null,
				args: [],
				time: 300
			}, param), time = new Date().getTime(), throttleId = fn.__throttleId;
			if (!fn.__prevtime) {
				fn.apply(p.context, p.args);
				fn.__prevtime = time;
			} else {
				if (time > fn.__prevtime + p.time) {
					fn.apply(p.context, p.args);
					fn.__prevtime = time;
				}
				// 最后一次执行
				_$.throttle(fn, param);
			}
		},
		// 获取事件触发位置
		getEventPosition: function(dom, e) {
			var rect = dom && dom.getBoundingClientRect(), event = e || window.event;
			return event && dom && {
				left: event.clientX - rect.left,
				top: event.clientY - rect.top,
				width: rect.width,
				height: rect.height
			};
		},
		// 获取相对父元素的位置
		getRelativePosition: function(dom) {
			var p = dom && dom.parentNode, pRect = p && p.getBoundingClientRect(), rect = dom && dom.getBoundingClientRect();
			if (pRect && rect) {
				return {
					left: rect.left - pRect.left,
					top: rect.top - pRect.top,
					w: rect.width,
					h: rect.height,
					width: pRect.width,
					height: pRect.height
				};
			}
		},
		// 设置相对位置
		setRelativePosition: function(dom, p, fn) {
			dom.style.left = (p.left !== undefined) && (p.left + 'px');
			dom.style.top = (p.top !== undefined) && (p.top + 'px');
			fn && fn();
		},
		// 获取相对位置百分比
		getPercentPosition: function(dom) {
			var p = dom && _$.getRelativePosition(dom);
			return p && {
				pX: parseFloat((p.left / (p.width - p.w)).toFixed(2)),
				pY: parseFloat((p.top / (p.height - p.h)).toFixed(2))
			};
		},
		// 设置百分比位置
		setPercentPosition: function(dom, p) {
			var rect = dom.getBoundingClientRect(), pRect = dom && dom.parentNode.getBoundingClientRect(),
			// 容器大小
			w = pRect.width - rect.width, h = pRect.height - rect.height, left, top;
			if (p.pX === 0 || p.pX === 1) {
				dom.style[(p.pX ? 'right' : 'left')] = '0px';
				dom.style[(p.pX ? 'left' : 'right')] = '';
			} else if (p.pX) {
				left = w * p.pX;
			}
			if (p.pY === 0 || p.pY === 1) {
				dom.style[(p.pX ? 'bottom' : 'top')] = '0px';
				dom.style[(p.pX ? 'top' : 'bottom')] = '';
			} else if (p.pY) {
				top = h * p.pY;
			}
			if (left || top) {
				_$.setRelativePosition(dom, {
					left: left,
					top: top
				});
			}
		},
		// 位置移动
		moveTo: function(dom, p, fn) {
			if (!dom || !p || dom.className.contains('_animate')) {
				return;
			}
			var startP = _$.getRelativePosition(dom), times = 10,
			// 位移
			left = p.left !== undefined ? p.left - startP.left : 0, top = p.top !== undefined ? p.top - startP.top : 0,
			// 单次位移
			x = left && (left / times), y = top && (top / times), exec = 0, move = function() {
				if (exec >= times) {
					// 删除动画className
					dom.className = dom.className.replace(/\s*(_animate)/, "");
					fn && fn();
					return;
				}
				setTimeout(function() {
					++exec;
					var p = {
						left: x === 0 ? undefined : (startP.left + x * exec).toFixed(),
						top: y === 0 ? undefined : (startP.top + y * exec).toFixed()
					};
					_$.setRelativePosition(dom, p, move);
				}, 10);
			}, className = dom.className || '';
			// 增加动画className
			dom.className = className ? className + ' _animate' : '_animate';
			move();
		},
		// 消息框
		message: function(type, content, okCall, cancelCall) {
			var bg = document.createElement('div'), container = document.createElement('div');
			bg.className = '_messageBg';
			container.className = '_msgContainer';
			document.body.appendChild(bg);
			document.body.appendChild(container);
			var title = '消息', createBtn = function(className, text, fn) {
				return '<div class="button ' + className + '">' + text + '</div>';
			}, cancelBtn = '';
			if (type === 'alert') {
				title = '提示';
				cancelCall = okCall;
			} else if (type === 'confirm') {
				title = '确认';
				cancelBtn = createBtn('greyBtn _cancelBtn', '取消');
			}
			// 消息头
			var header = ['<div class="_msgHeader">', title, '<span class="_closeIcon">×</span></div>'].join(''),
			// 消息内容
			content = ['<div class="_msgContent">', content, '</div>'].join(''),
			// 消息脚
			footer = ['<div class="_msgFooter">', cancelBtn, createBtn('_okBtn', '确认'), '</div>'].join('');

			container.innerHTML = (header + content + footer);
			_$.on(container, 'click', function(e) {
				e = e || window.event;
				var target = e.target || e.srcElement,
				// 确认、取消或关闭
				cancel = target.className.contains('_cancelBtn') || target.className.contains('_closeIcon'), ok = target.className.contains('_okBtn');
				if (ok || cancel) {
					if (ok) {
						okCall && okCall.call();
					} else {
						cancelCall && cancelCall.call();
					}
					document.body.removeChild(bg);
					document.body.removeChild(container);
				}
				// 阻止事件冒泡
				if (e.stopPropagation) {
					e.stopPropagation();
				} else {
					window.event.cancelBubble = true;
				}
			});
		},
		// 提示
		alert: function(content, okCall) {
			_$.message('alert', content, okCall);
		},
		// 确认
		confirm: function(content, okCall, cancelCall) {
			_$.message('confirm', content, okCall, cancelCall);
		},
		// 判断是否包含class
		hasClass: function(dom, className) {
			return new RegExp('(^|\\s)' + className + '(\\s|$)').test(dom.className);
		},
		// 增加class
		addClass: function(dom, className) {
			var eleClass = dom.className;
			_$.each(className.split(/\s+/) || [], function() {
				if (this.length && !_$.hasClass(dom, this.toString())) {
					eleClass = eleClass.trim() + ' ' + this;
				}
			});
			dom.className = eleClass;
		},
		// 删除class
		removeClass: function(dom, className) {
			var eleClass = dom.className;
			_$.each(className.split(/\s+/) || [], function() {
				if (this.length && _$.hasClass(dom, this.toString())) {
					eleClass = eleClass.replace(new RegExp('(^|\\s)' + this + '(\\s|$)'), ' ').trim();
				}
			});
			dom.className = eleClass;
		}
	};
	return utils;
});